package helper.com.utils;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;

/**
 * @author 大忽悠
 * @create 2022/5/18 10:27
 */
@Component
@RequiredArgsConstructor
public class RedisUtil {
    private final StringRedisTemplate stringRedisTemplate;
    private final String INCR_PREFIX="incr:";
    private final String INCR_DELIMITER=":";
    /**
     * 位运算向高位移动的位数,为了给redis自增长key腾出32位的空间
     */
    private final int COUNT_BITS=32;
    private static final long BEGIN_TIMESTAMP;

    static {
        //计算开始时间戳
        BEGIN_TIMESTAMP= LocalDateTime.of(2002, 1, 2, 0, 0, 0).toEpochSecond(ZoneOffset.UTC);
    }

    /**
     * 生成全局唯一ID
     * 符号位默认为0(1 bit)-时间戳(32 bit)-序列号(32 bit)
     * example: 如果要为店铺生成全局唯一ID,keyPrefix为shop
     * 那么用于累加的全局唯一key为incr:shop:2022 ---默认按照年分割(small app)
     */
    public long generatorUniqueId(String keyPrefix){
        //计算32 bit的时间戳
        long timeStampGap=LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)-BEGIN_TIMESTAMP;
        //notice: redis单个key的自增长有上限,最大为2的64次方,如果自增长key不存在,redis会自动创建一个
        //thus: 累加使用的key不能一直用一个,这里小应用,默认一年换一个
        int year = LocalDateTime.now().getYear();
        //获得序列号
        Long increment = stringRedisTemplate.opsForValue().increment(INCR_PREFIX + keyPrefix + INCR_DELIMITER + year);
        return timeStampGap << COUNT_BITS | increment;
    }
}
